/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CONFIG_HH
#define CONFIG_HH
//! \addtogroup intromit_core
//@{

// INCLUDES
#include <stdlib.h>

// TYPEDEFS
typedef enum
{
    CONFIG_PAIR_BLOCK=0,
    CONFIG_PAIR_VARIABLE,
    CONFIG_PAIR_UNKNOWN
} config_pair_type;

// CLASSES

//! Hierchical entities of parsed config file
class config_pair
{
    config_pair_type type;
    char *key, *value;
    int level, line;

public:
    void ctor();
    void dtor();

    //! @name Setters
    //@{
    inline void set_type(config_pair_type type_) {type=type_;}
    inline void set_level(int level_) {level=level_;}
    inline void set_line(int line_) {line=line_;}
    void set_key(char *key, int n=-1);
    void set_key_lowercase(char *key, int n=-1);
    void set_value(char *value, int n=-1); //@}

    //! @name Getters
    //@{
    inline config_pair_type get_type() {return type;}
    inline int get_level() {return level;}
    inline int get_line() {return line;}
    inline char *get_key() {return key;}
    inline char *get_value() {return value;} //@}
};

//! Config file parser and browser
class config
{
    // data origin
    char *filename;
    char *data;
    int n_data;

    // config pairs
    config_pair *pair;
    int n_pair, max_pair;

    // ** PRIVATE FUNCTIONS **
    bool parse();
    bool parse_tag(int &i, int *is_end, char **key, int *n_key, char **value, int *n_value);
    bool parse_line(int &i, char **key, int *n_key, char **value, int *n_value);
    bool parse_error(int i, const char *error, char *key=NULL);
    void parse_string(int &i);
    void parse_comment(int &i);
    int get_line(int pos, int *col=NULL);
    int get_parent(int i_pair);

public:
    config();
    ~config();

    //! @name Init config with a filename
    //@{
    void init_pairs();
    bool init_filename(char *filename); //@}

    //! @name Browsing: skip, locate blocks
    //@{
    bool search_block(char *key, char *value, int *ini, int *end, int from=0);
    int skip_block(int i_block); //@}

    //! @name Getters
    //@{
    inline int get_n_pair() {return n_pair;}
    inline config_pair *get_pair(int i) {return &pair[i];}
    inline char *get_filename() {return filename;} //@}

    //! @name Error checking/parsing
    //@{
    bool check_type(int i_pair, config_pair_type type);
    bool check_valued(int i_pair);
    bool check_valued_variable(int i_pair);
    bool check_valued_block(int i_pair);
    bool check_unvalued_variable(int i_pair);
    bool error_invalid_key(int i_pair, const char **valid_keys=NULL);
    bool error_invalid_position(int i_pair, const char *required_position);
    bool error_invalid_type(int i_pair);
    bool error_value(int i_pair);
    bool error_no_value(int i_pair);
    bool error_no_id(int i_pair);
    bool error_no_section(const char *section); //@}

    //! @name Debug
    void dump(char *filename=NULL);
};

//@}
#endif
